/*
 * Copyright 2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.seppiko.chart.controllers

import org.seppiko.chart.exceptions.SeppikoProcessorException
import org.seppiko.chart.models.ResponseMessage
import org.seppiko.chart.services.DecodeService
import org.seppiko.chart.utils.JsonUtil.fromJsonObject
import org.seppiko.chart.utils.LoggingManager
import org.seppiko.chart.utils.ResponseUtil
import org.seppiko.commons.utils.StringUtil
import org.seppiko.commons.utils.codec.Base64Util
import org.seppiko.commons.utils.http.HttpClientException
import org.seppiko.commons.utils.http.HttpClientUtil
import org.seppiko.commons.utils.http.HttpMethod
import org.seppiko.commons.utils.http.HttpRuntimeException
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import java.io.BufferedInputStream
import java.io.ByteArrayInputStream
import java.io.IOException
import java.io.InputStream
import java.net.URISyntaxException
import java.net.URL

/**
 *
 * @author Leonard Woo
 */
@RestController
class DecodeController {
  private val logger: LoggingManager = LoggingManager.INSTANCE.getLogger(DecodeController::class.qualifiedName!!)

  @Autowired
  private lateinit var service: DecodeService

  @GetMapping("/decode")
  fun decodeGetContentHandleExecution(): ResponseEntity<ByteArray> {
    return ResponseMessage.sendJsonResp(405, 405, "Method Not Allowed.Only POST")
  }

  @PostMapping("/decode")
  fun decodePostContentHandleExecution(@RequestBody body: String): ResponseEntity<ByteArray> {
    if (StringUtil.isEmpty(body)) {
      return ResponseMessage.sendJsonResp(404, 404, "Not found any request.")
    }

    val root = fromJsonObject(body)
      ?: return ResponseMessage.sendJsonResp(404, 404, "Not found any data.")
    val type = root["type"].asText().lowercase()
    val data = root["data"].asText()

    var input: InputStream?
    if (type == "base64") {
      //iVBO
      input = ByteArrayInputStream(Base64Util.decode(data))
    } else if(type == "uri") {
      //
      try {
        input = BufferedInputStream(URL(data).openStream())
      } catch (ex: IOException) {
        logger.warn("Image didn't exist", ex)
        return ResponseMessage.sendJsonResp(404, 404, "URI decode failed.")
      }
    } else if(type == "url") {
      //http://localhost/qr.png
      try {
        val resp = HttpClientUtil.sendRequest(data, HttpMethod.GET, 20, null, "", InputStream::class.java, null)
        input = resp.body() as InputStream?
      } catch (e: URISyntaxException) {
        return ResponseMessage.sendJsonResp(404, 404, "Data is not URL syntax.")
      } catch (e: HttpClientException) {
        return ResponseMessage.sendJsonResp(404, 404, "URL content acquisition failed.")
      } catch (e: HttpRuntimeException) {
        return ResponseMessage.sendJsonResp(404, 404, "URL content acquisition failed.")
      }
      if (input == null) {
        return ResponseMessage.sendJsonResp(404, 404, "URL content acquisition failed.")
      }
    } else {
      return ResponseMessage.sendJsonResp(400, 400, "Unsupported type.")
    }

    return try {
      val se = service.decodeCHX(input)
      ResponseUtil.sendResponse(200, se.type, se.data!!)
    } catch (e: SeppikoProcessorException) {
      ResponseMessage.badRequest(e.code, e.message)
    }
  }

}